package com.feng.security.jarsigner;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.sql.Blob;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;

import org.apache.commons.logging.LogFactory;

public class JarSigner {
	private static final String AMS_APP_UPLOAD_ROOTPATH = null;
	private static final String AMS_APP_UPLOAD_JAR = null;
	private static final String SYS_KEYSTORE_FILE_PATH = null;
	private static final String SYS_KEYSTORE_KEY_ALIAS = null;
	private static String SYS_KEYSTORE_STORE_PASSWD;
	private static String SYS_KEYSTORE_KEY_PASSWD;

	/**
	 * 图片类型(1：快照，2：宣传图,0:jar,3:图标,4：需求,5：测试,6：正式lca包 ,7:试用版应用包 ,8:试用版本lca包,9:正式版本jar类型jad文件 10:试用版本jar类型jad文件)
	 */
  	/**
  	 * 
  	 * @param amsAppFrom
  	 * @param amsAppsubmitInfo
  	 * @param isLiteVersion true:试用 false 正式
  	 * @return 1 成功 -1 主包不存在 -2 jad不存在 -3 生成xml文件出错  -4 lca临时文件不存在 -5 签名出错 -6 没有初始化联想认证文件 -7 不是联想公钥
  	 * @throws LmmException 
  	 * @throws IOException 
  	 * @throws SQLException 
  	 */
	public static synchronized int  autoJar(boolean isLiteVersion,Long oldLong) {
	    String filePath_jar = AMS_APP_UPLOAD_JAR;
	    List tempListImg = new Vector();
	    Long file_one=0L;
	    Long file_two=9L;
	    if(isLiteVersion){
	    	file_one=7L;
	    	file_two=10L;
	    }
        boolean isOldBlob=false;
        boolean isOldBlobJad=false;
    	File lca_tempFile=null;
    	String reg="(\\.{1}[^\\.]*?$)";//最后的扩展名
        try{
			Blob amsAppsubmitImageApkJar = null;
			String amsAppsubmitImageApkJar_path = "";
			Blob amsAppsubmitImageJad = null;
			Blob amsAppsubmitImageLca = null;
			if (amsAppsubmitImageApkJar == null) {
				// 从数据库读取
				java.sql.Blob blob = null;// apk文 件;
				if (blob != null) {
					amsAppsubmitImageApkJar = blob;
					isOldBlob = true;
				} else {
					// 出错
					return -1;
				}
    		 }
	    	
	    	String jarfilePre= AMS_APP_UPLOAD_ROOTPATH+("/"+amsAppsubmitImageApkJar_path);
	    	jarfilePre=jarfilePre.replaceAll("/+","/");
	    	File jarFile_temp=new File(jarfilePre);//改名

	    	lca_tempFile=new File(jarFile_temp.getParentFile(),jarFile_temp.getName().replaceAll(reg, ".lca_temp"));
	 		java.io.FileOutputStream fileOutputStream=new FileOutputStream(lca_tempFile);
	 		JarOutputStream out = new JarOutputStream(fileOutputStream);
	        InputStream in = amsAppsubmitImageApkJar.getBinaryStream();
	        addJarEntry(out ,in,jarFile_temp.getName());
	        in.close();
	        if(isOldBlob){
	        	amsAppsubmitImageApkJar = null;
	        }	   
	 		try{
	 		//写入xml流
	 		//if(amsAppsubmitInfo.getPackageTypeId()==1){
		 		//jad java包上传jad
	 			Document doc = getLcaXml(amsAppsubmitInfo,isLiteVersion);
	 			String docXml=getDocString(doc);
		        in=new java.io.ByteArrayInputStream(docXml.getBytes());
		        addJarEntry(out ,in,"Lcainfo.xml");
		        in.close();
	 		//}
	 		}catch(Exception e){
	 			return -3;
	 		}
	        out.close();
	        
			com.lenovo.lps.appstore.security.AesCrypto aesCrypto=new AesCrypto();
			SYS_KEYSTORE_STORE_PASSWD = aesCrypto.decrypt(SYS_KEYSTORE_STORE_PASSWD);
			SYS_KEYSTORE_KEY_PASSWD = aesCrypto.decrypt(SYS_KEYSTORE_KEY_PASSWD);
			String keyFilePath = SYS_KEYSTORE_FILE_PATH;
            keyFilePath=keyFilePath.replaceAll("\\+", "/");
	        int isExistFile=checkKeystoreIsExist(appDelegate, SYS_KEYSTORE_STORE_PASSWD,SYS_KEYSTORE_KEY_PASSWD, SYS_KEYSTORE_KEY_ALIAS );
	        if(isExistFile!=1){
	        	//没有初始化联想认证文件或过期
	        	if(isExistFile==-3){
	        		return -7;//
	        	}
	        	return -6;
	        }
	        
	      //记名
	        //jarsigner  -storepass lenovo -keystore D:\application\Jdk\jdk1.6.0_06\bin\.keystore   xxxxx.jar trialkey
	        //检查 keystore 一定要 -debug
	       // keytool -list -v  -debug -keystore D:\application\Jdk\jdk1.6.0_06\bin\.keystore -alias trialkey -storepass lenovo	       
	        
	        //String  arg="-list -v  -debug -keystore "+keyFilePath+" -alias trialkey -storepass lenovo";
	        
	        String  arg="-list -v  -debug  -keystore "+keyFilePath+" -alias "+SYS_KEYSTORE_KEY_ALIAS+" -keypass "+SYS_KEYSTORE_KEY_PASSWD+" -storepass "+SYS_KEYSTORE_STORE_PASSWD+"";
	        try{
	        	sun.security.tools.KeyTool.main(arg.split("\\s+"));
	        }catch(Exception e){   
	        	return -7;
	        }
	        if(lca_tempFile.exists()){
	        	try{
		        	arg="-storepass "+SYS_KEYSTORE_STORE_PASSWD+"  -keypass "+SYS_KEYSTORE_KEY_PASSWD+" -keystore "+keyFilePath+"  "+lca_tempFile.getAbsolutePath()+" "+SYS_KEYSTORE_KEY_ALIAS;
		 			String []args = arg.split("\\s+");
		 			sun.security.tools.JarSigner.main(args);
					String newName = lca_tempFile.getName().replaceAll("_temp$", "");
		 			File newLcaFile=new File(lca_tempFile.getParentFile(),newName);
		 			if(newLcaFile.exists()){
		 				newLcaFile.delete();
		 			}
		 			File oldFile=new File(newLcaFile.getParentFile(),"old"+newLcaFile.getName());
		 			if(newLcaFile.exists()){
		 				newLcaFile.renameTo(oldFile);
		 			}
		 			if(!lca_tempFile.renameTo(newLcaFile)){
		 				oldFile.renameTo(newLcaFile);
		 			}else{
		 				if(oldFile.exists()){
		 					oldFile.delete();
			 			}
		 			}
	        	}catch(Exception e){
	        		return  -5;
	        	}
	        }else{
	        	//lca包不存在
	        	return -4;
	        }
			AmsAppsubmitImage amsAppsubmitImage=new AmsAppsubmitImage();
			amsAppsubmitImage.setAvailable(1L);
			
			String newFileStr = amsAppsubmitImageApkJar_path.replaceAll(reg, ".lca");
			File lcaFile=new File(newFileStr);
			amsAppsubmitImage.setImagePath(newFileStr);
			amsAppsubmitImage.setImageTime(new Date());
			amsAppsubmitImage.setImageName(lcaFile.getName());
			if(oldLong!=null){
				amsAppsubmitImage.setImageId(oldLong);
			}
			addBlob(amsAppsubmitImage);
	        if(!isLiteVersion){
	    		amsAppsubmitImage.setImageType(6L);//appimgsFile_0.getContentType());
	        }else{
	        	amsAppsubmitImage.setImageType(8L);//appimgsFile_0.getContentType());
	        }
	        amsAppsubmitInfo.getAmsAppsubmitImages().add(amsAppsubmitImage);
	        return 1;// 成功
        }catch(Exception e){
			if(lca_tempFile!=null&&lca_tempFile.exists()&&lca_tempFile.isFile()){
				lca_tempFile.delete();
			}
        }
	    return -1;
	}
	
	/**
	 * jar 新的jar添加文件
	 * @param out
	 * @param in
	 * @param fileName
	 * @return 1 成功 -1 失败
	 */
	private static int addJarEntry(JarOutputStream out ,InputStream in,String fileName){
 		//jad java包上传jad
		JarEntry e = new JarEntry(fileName);
        try {
			out.putNextEntry(e);
	 		int bytesRead = 0;
	 		byte []buffer =null;
	
	 		buffer = new byte[in.available()];
	 		while ((bytesRead = in.read(buffer))>0) {
	 			out.write(buffer,0,bytesRead); 			
	 			
	 		}
	 		out.flush();		
	 		out.closeEntry();		
	 		return 1;
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		return -1;
	}	
	 /**
	  * 上传信息转换lca需要的xml信息
	  * @param amsAppsubmitInfo
	  * @return
	  */
	  private  org.jdom.Document getLcaXml(AmsAppsubmitInfo amsAppsubmitInfo,boolean isLite){
		  	String deviceSupport;
			Long appid = 0l;
			String versionCode = "0";
			String suportMinVersion;
			String appName = "";
			Long authcode = 0L;
			Boolean isWidget = true;
			Long pushAppType = 0L;
			Long pushContentsId = 0L;
			String sid = "";
			boolean pushEnable = true;
			String typeDeclare;
			
			StringBuffer xml = new StringBuffer();
			xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			xml.append("<lcainfo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">");
			xml.append("<platform><![CDATA[" + deviceSupport + "]]></platform>");
			xml.append("<mini-lca-sdk-version><![CDATA[" + suportMinVersion + "]]></mini-lca-sdk-version>");
			xml.append("<appid><![CDATA[" + appid + "]]></appid>");
			xml.append("<version><![CDATA[" + versionCode + "]]></version>");
			xml.append("<name><![CDATA[" + appName + "]]></name>");
			xml.append("<demoversion><![CDATA[" +isLite+ "]]></demoversion>");
			xml.append("<apptype><![CDATA[" + typeDeclare + "]]></apptype>");
			
			xml.append("<authcode><![CDATA[" + authcode + "]]></authcode>");
			if (pushEnable) {
				xml.append("<push>");
				xml.append("<push-app-type><![CDATA[" + pushAppType + "]]></push-app-type>");
				if (pushAppType == 0) {
					xml.append("<cmtype><![CDATA[" + pushContentsId + "]]></cmtype>");
				}
				xml.append("<sid><![CDATA[" + sid + "]]></sid>");
				xml.append("</push>");
			}
			xml.append("<widget><![CDATA[" + isWidget + "]]></widget>");
			xml.append("</lcainfo>");
			//os.write(xml.toString().getBytes("UTF-8"));
			org.jdom.input.SAXBuilder SAXBuilder=new SAXBuilder();
			java.io.StringReader xmlReader=new StringReader(xml.toString());
			try {
//				org.jdom.output.XMLOutputter dd=new XMLOutputter();
//				dd.output(SAXBuilder.build(xmlReader), new JarOutputStream(System.out));
				return SAXBuilder.build(xmlReader);
			} catch (Exception e) {
				LogFactory.getLog(AppLogicBean.class).error("应用信息生成lcaXml文件出错:"+e.getLocalizedMessage());
			}
			return null;

	  }
	  /**
		 * 检查是存在联想认证文件
		 * 如果没有则成数据库取认证文件
		 * @return 1 存在 -1 异常　-2　数据库没有初始化联想认证文件 -3 密钥过期
		 */
		private  synchronized int checkKeystoreIsExist(final String SYS_KEYSTORE_STORE_PASSWD,final String SYS_KEYSTORE_KEY_PASSWD, final String SYS_KEYSTORE_KEY_ALIAS){
			String SYS_KEYSTORE_BLOB="SYS_KEYSTORE_BLOB";
			String SYS_KEYSTORE_FILE_PATH="SYS_KEYSTORE_FILE_PATH";
			try {
				File keyFilePathFile = new File(SYS_KEYSTORE_FILE_PATH);
				//如果指的路径找不到文件，从数据库里读取
				if(!keyFilePathFile.exists()){//||!keyFilePathFile.isFile()
					Blob keyStore_blob = null;//从数据库里取keystore文件
					if(keyStore_blob ==null || keyStore_blob.length()==0){
						return -1;
					}else{  
						java.io.InputStream in = keyStore_blob.getBinaryStream();
						long length = FileUtil.saveFileStream(in, keyFilePathFile.getName(), keyFilePathFile.getParentFile().getCanonicalPath().replaceAll("\\+", "/"));
						if(length==0){
							return -2;
						}
					}
					boolean isOk = checkValidity(new File(SYS_KEYSTORE_FILE_PATH) ,SYS_KEYSTORE_KEY_ALIAS,SYS_KEYSTORE_STORE_PASSWD);//"lenovo"
					if(!isOk){
						return -3;// 密钥过期
					}
				}else{
					boolean isOk = checkValidity(keyFilePathFile ,SYS_KEYSTORE_KEY_ALIAS,SYS_KEYSTORE_STORE_PASSWD);
					if(!isOk){
						keyFilePathFile.delete();
						checkKeystoreIsExist(SYS_KEYSTORE_STORE_PASSWD,SYS_KEYSTORE_KEY_PASSWD, SYS_KEYSTORE_KEY_ALIAS );
					}
				}
				return 1;

			} catch (Exception e) {
				return -1;
			}
		}
		
		/**
		 * 
		 * @param fis
		 * @param alias 
		 * @param password 密码：keystore password
		 * @return
		 */
	private  boolean checkValidity(InputStream fis, String alias,
			String password) {
		try {
			KeyStore ks = KeyStore.getInstance("JKS");
			ks.load(fis, password.toCharArray());
			java.security.cert.Certificate certificate = ks.getCertificate(alias);
			X509Certificate certificate509 = (X509Certificate) certificate;
			X509Certificate c = certificate509;
			c.checkValidity(new Date(System.currentTimeMillis() - 2000 * 20));
		} catch (Exception ex) {
			LogFactory.getLog(AppLogicBean.class).error("检查联想密钥有效期失败", ex);
			return false;
		}
		return true;
	}
}
